/**
 * @file acpibatt.c
 * ACPI battery source for TrayInfo.
 */

/* ACPI battery support added by Laszlo Ashin <kodest@gmail.com> */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "trayinfo.h"
#include "utils.h"

/** Source handle. */
static source_handle_t *acpibatt_sh;

/**
 * Collects data and prints the obtained information in a nice form.
 * @param now Current time at calling. (Unused)
 * @param fd File descriptor associated with the source. (Unused)
 * @return Number of characters printed.
 */
static int
acpibatt_write(double now, int fd)
{
	static const char *idlist[] = {
		"charging state",
		"remaining capacity",
		"present rate"
	};
	static const char *infoidlist[] = {
		"last full capacity"
	};
	char *vallist[] = { NULL, NULL, NULL };
	double rem, rate, cap;
	enum { unknown, discharging, charging, charged } state = unknown;
	char *ep;
	int r;

	collect_data_from_file(
		"/proc/acpi/battery/BAT0/state",
		":", 3, idlist, vallist
	);
	if (vallist[0]) {
		if (!strcmp(vallist[0], "discharging")) {
			state = discharging;
		} else if (!strcmp(vallist[0], "charging")) {
			state = charging;
		} else if (!strcmp(vallist[0], "charged")) {
			state = charged;
		}

		free(vallist[0]);
	}
	if (vallist[1]) {
		r = parse_prefixed_string(vallist[1], &rem, &ep);
		if (r || ep[0] != 'W' || ep[1] != 'h') {
			rem = 0.0f;
		}

		free(vallist[1]);
	}
	if (vallist[2]) {
		r = parse_prefixed_string(vallist[2], &rate, &ep);
		if (r || ep[0] != 'W') {
			rate = 0.0f;
		}

		free(vallist[2]);
	}
	switch (state) {
	case discharging:
		return show("%.0fm", rem * 60.0f / rate);
	case charging:
		vallist[0] = NULL;
		collect_data_from_file(
			"/proc/acpi/battery/BAT0/info",
			":", 1, infoidlist, vallist
		);
		if (vallist[0]) {
			r = parse_prefixed_string(vallist[0], &cap, &ep);
			if (r || ep[0] != 'W' || ep[1] != 'h') {
				cap = 0.0f;
			}

			free(vallist[0]);
		}
		return show("%+.0fm", (cap - rem) * 60.0f / rate);
	case charged:
		return show("full");
	case unknown:
		return show("batt?");
	}
	return 0;
}

/**
 * Init function of the module.
 * @param phase Phase of the module's life.
 * @return Zero on success.
 */
int
init_module(module_phase_t phase)
{
	switch (phase) {
	case MODULE_PHASE_INIT: {
		source_t source = {
			.name = "acpibatt",
			.write = acpibatt_write,
		};
		acpibatt_sh = register_source(&source);
		return (acpibatt_sh == NULL);
	}
	case MODULE_PHASE_EXIT:
		return forget_source(acpibatt_sh);
	}
	return 0;
}
